Refactor how we build pagination response to support collections in SQL#3521
Refactor how we build pagination response to support collections in SQL#3521aaronburtle wants to merge 6 commits intomainfrom
Conversation
|
@copilot can you review this PR please? |
I reviewed the PR changes in e0de2b2 and didn’t find blockers in the pagination refactor or the added unit coverage. I did attempt to run the targeted |
…s://github.com/Azure/data-api-builder into dev/aaronburtle/Fix-Pagination-Column-Response
There was a problem hiding this comment.
Pull request overview
This PR refactors REST/MCP pagination response shaping so pagination metadata (nextLink for REST, after for MCP) is returned out-of-band in the response envelope instead of being encoded into the row array, addressing issue #3462 around ambiguity with array-shaped JSON payloads.
Changes:
- Refactors
SqlResponseHelpers.FormatFindResultto build paginated envelopes directly ({ value, nextLink }/{ value, after }) and simplifiesOkResponseto only wrap results in{ value: [...] }. - Renames/changes the pagination next-link builder in
SqlPaginationUtilto return a plain string URI. - Adds focused unit tests to pin envelope shapes for empty/single/collection/paginated responses and an attempted regression guard.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| src/Service.Tests/UnitTests/SqlResponseHelpersUnitTests.cs | Adds unit tests for FormatFindResult envelope shapes and pagination metadata behavior. |
| src/Core/Resolvers/SqlResponseHelpers.cs | Moves pagination metadata out-of-band; simplifies OkResponse; adds guard in extra-field detection. |
| src/Core/Resolvers/SqlPaginationUtil.cs | Replaces JSON-element nextLink builder with a string-returning URI builder and updates docs. |
|
@copilot I addressed your comments, can you do another review please? |
Reviewed again on the latest commits (including e347cab). The previous API-compat concerns are addressed (signatures restored), and the regression coverage now includes the top-level array-tail sentinel case. I don’t see new blockers. I re-ran the targeted |
Why make this change?
Closes #3462
What is this change?
Refactors how SQL Find responses signal pagination so it no longer relies on the JSON shape of the result list.
Previously,
SqlResponseHelpers.FormatFindResultappended pagination metadata to the row collection as an in-band sentinel a single-element JSON array wrapping{ "nextLink": ... }(REST) or{ "after": ... }(MCP) andOkResponserecovered it by checking whether the last element of the result list was aJsonValueKind.Array. This worked only because SQL backends never produced array-shaped row values.That assumption breaks with SQL Server's
JSONtype,JSON_ARRAY(),vector, and other collection-shaped column values a real data row could carry an array-shaped tail value and be misclassified as a pagination envelope.This change carries pagination metadata out-of-band:
FormatFindResultbuilds the response envelope directly as a typed projection ({ value, nextLink }for REST,{ value, after }for MCP) using abool hasNextlocal instead of encoding the decision into the row collection.OkResponse(JsonElement, bool?)is reduced to a single-responsibility envelope wrapper. The signature is preserved (isMcpRequestis now optional and accepted-but-unused) so existing callers ofMicrosoft.DataApiBuilder.Corecontinue to compile and link unchanged. The shape-detection branch is removed from the body.GetConsolidatedNextLinkForPaginationis preserved with its original signature andJsonElementreturn type for source compatibility. Internally,FormatFindResultnow constructs the next-page URL inline (it needs the URL as astringto put into the typed response envelope), avoiding a serialize-then-parse round-trip just to satisfy the old wrapper shape.DetermineExtraFieldsInResponsegains aJsonValueKind.Objectguard so future array/scalar/collection-typed row shapes return an empty extra-fields set rather than throwing onEnumerateObject().!null-forgiving operator, standardizedJsonValueKindchecks onis, refreshed stale comments and XML docs, removed dead commented-out code.Wire format is unchanged for both REST and MCP. Public API surface is byte-identical to
mainno signatures added, removed, or renamed; no[Obsolete]warnings emitted to downstream consumers. The new gate:is logically equivalent to the original gate.
How was this tested?
Added seven focused unit tests in
SqlResponseHelpersUnitTests.cspinning the envelope shape across every branch:nextLink)after)All seven pass.
dotnet format --verify-no-changesis clean across the touched files.